home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 19 / CD_ASCQ_19_010295.iso / dos / prg / pas / swag / win_os2.swg / 0018_Windows Statusline Unit.pas < prev    next >
Pascal/Delphi Source File  |  1994-02-05  |  19KB  |  497 lines

  1. (**************************************************************************
  2.  *                                                                        *
  3.  * STATUS.PAS - A Statusline unit, by Thomas S. Carlisle                  *
  4.  *              Free for public use, all I ask is that my name remain     *
  5.  *              with this code.                                           *  
  6.  *                                                                        *
  7.  * This unit provides easy implementation of a status line. The           *
  8.  * statusline will be at the bottom of the screen, and will take on the   *
  9.  * colors defined in the system as button face, and button shadow.        *
  10.  *                                                                        *
  11.  * The statusline can have multiple partitions to display different       *
  12.  * information. For example, you could have a partition that displays     *
  13.  * a clock (see STATUSEX.PAS), another one that displays the current      *
  14.  * file open in a word processing application, or virtually anything you  *
  15.  * can think up.                                                          *
  16.  *                                                                        *
  17.  * The main object is TStatusLine. TStatusline is an abstract object with *
  18.  * limited default functionality. TStatusline is a statusline with no     *
  19.  * partitions. It knows how to draw itself, and most importantly it knows *
  20.  * how to insert partitions. However, TStatusline does not Insert any     *
  21.  * partitions. The user must create a descendant object of TStatusLine    *
  22.  * that overrides the Setup method to insert some partitions.             *
  23.  *                                                                        *
  24.  * A typical Setup method may look something like this:                   *
  25.  *  PROCEDURE TMyStatusline.Setup;                                        *
  26.  *  BEGIN                                                                 *
  27.  *       InsertItem(100,DrawProc);                                        *
  28.  *  END;                                                                  *
  29.  *                                                                        *
  30.  * That would insert a partition that is 100 pixels wide. The second      *
  31.  * parameter is important. It is a procedure. Each partition must be      *
  32.  * passed a procedure so it knows who to call to fill in the partition    *
  33.  * with the appropriate text. The procedure passed in the InsertItem      *
  34.  * statement MUST be a procedure that was previously declared like this:  *
  35.  *                                                                        *
  36.  * PROCEDURE DrawProc(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);FAR;  *
  37.  * BEGIN                                                                  *
  38.  *     { your custom draw code goes here... }                             *
  39.  * END;                                                                   *
  40.  *                                                                        *
  41.  * Note proceduremust be declared as FAR. It also MUST have the exact     *
  42.  * parameter list as shown. In the body, you can do what you want. A      *
  43.  * simple example would be to simply write out a line of text:            *
  44.  *                                                                        *
  45.  * PROCEDURE DrawProc(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);FAR;  *
  46.  * BEGIN                                                                  *
  47.  *     TextOut(PaintHdc,3,1,'Test',4);                                    *
  48.  * END;                                                                   *
  49.  *                                                                        *
  50.  * Usually you will not have a simple procedure like that. For a better,  *
  51.  * more functional example see the procedure Clock in STATUSEX.PAS        *
  52.  *                                                                        *
  53.  *************************************************************************)
  54.  
  55. UNIT Status;
  56.  
  57. INTERFACE
  58.  
  59. USES
  60.     WObjects,WinTypes,WinProcs,WinCrt;
  61.  
  62. TYPE
  63.     TPaintProc = PROCEDURE(PaintHdc : HDC; VAR PaintInfo : TPaintStruct);
  64.  
  65.     PPartitionCollection = ^TPartitionCollection;
  66.  
  67.     TPartitionCollection = OBJECT(TCollection)
  68.     END;
  69.  
  70.     PPartition = ^TPartition;
  71.  
  72.     TPartition = OBJECT(TWindow)
  73.         PRIVATE
  74.          LeftPosition,
  75.          RightPosition  : WORD;
  76.          PaintProc      : TPaintProc;
  77.          CONSTRUCTOR Init(AParent : PWindowsObject; ATitle : PCHAR;
  78.                LPos,RPos : WORD; Proc : TPaintProc);
  79.          PROCEDURE Paint(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);
  80.               VIRTUAL;
  81.     END;
  82.     
  83.     PStatusLine = ^TStatusLine;
  84.  
  85.     TStatusLine = OBJECT(TWindow)
  86.         CONSTRUCTOR Init(AParent : PWindowsObject; ATitle : PCHAR);
  87.         PROCEDURE Paint(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);
  88.               VIRTUAL;
  89.         DESTRUCTOR Done;VIRTUAL;
  90.         PROCEDURE InsertItem(StrLength : WORD; Proc : TPaintProc);
  91.         PROCEDURE Setup;VIRTUAL;
  92.         FUNCTION GetPartition(Index : BYTE):PPartition;VIRTUAL;
  93.         PRIVATE
  94.          Partitions     : PPartitionCollection;        
  95.     END;
  96.  
  97. IMPLEMENTATION
  98.  
  99. (************************** TPartition Methods ***************************)
  100.  
  101. { TPartition is an object descendant of TWindow. All TPartition objects
  102.   are child windows with TStatusLine as the parent.
  103.  
  104.   When a TPartition is inserted in the statusline, it is automaticlly
  105.   inserted right next to the previous TPartition on the statusline.
  106.  
  107.   The Init constructor method is called whenevr a new TPartition is
  108.   inserted in the statusline. The parameters of Init include the
  109.   TPartition's parent window, its title (Nil), the TPartitions left position
  110.   on the statusline, it's right position on the statusline, and most
  111.   importantly -- the last parameter -- is a procedure parameter. This
  112.   procedure parameter is a user defined procedure that will be used by
  113.   the TPartition.Paint method.
  114.  
  115.   Each TPartition knows how to draw itself, with the Paint method. The Paint
  116.   method draws an empty partition (i.e - only the frame, not filled with
  117.   text. The paint method calls the user defined procedure, which is
  118.   responsible for filling the partition frame with the appropriate text.
  119.  
  120.   See STATUSEX.PAS for an example of the user defined procedure           }
  121.     
  122.  
  123. CONSTRUCTOR TPartition.Init(AParent : PWindowsObject; ATitle : PCHAR;
  124.        LPos,RPos : WORD; Proc : TPaintProc);
  125.  
  126. VAR
  127.    R   : TRect;
  128. BEGIN
  129.      TWindow.Init(AParent,ATitle);
  130.      LeftPosition:=LPos;
  131.      RightPosition:=RPos;
  132.      PaintProc:=Proc;
  133.      WITH Attr DO BEGIN
  134.           Style:=Style OR ws_Child;
  135.           X:=LPos;
  136.           Y:=0;
  137.           W:=RPos-LPos;
  138.           H:=17;
  139.      END;
  140. END;
  141.  
  142. PROCEDURE TPartition.Paint(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);
  143. VAR
  144.    R : TRect;
  145.    TheBrush,
  146.    OldBrush     : HBrush;
  147.    Pen,
  148.    OldPen       : HPen;
  149. BEGIN
  150.      GetClientRect(HWindow,R);
  151.      TheBrush:=CreateSolidBrush(GetSysColor(color_BtnFace));
  152.      FillRect(PaintHdc,R,TheBrush);
  153.      DeleteObject(TheBrush);
  154.  
  155.      SetBkColor(PaintHdc,GetSysColor(color_BtnFace));
  156.      PaintProc(PaintHdc,PaintInfo);
  157.  
  158.      Pen:=CreatePen(ps_Solid,1,RGB(255,255,255));
  159.      OldPen:=SelectObject(PaintHDC,Pen);
  160.      MoveTo(PaintHDC,R.Left,R.Top);
  161.      LineTo(PaintHDC,R.Right,R.Top);
  162.      MoveTo(PaintHdc,R.Left,R.Top);
  163.      LineTo(PaintHdc,R.Left,R.Bottom);
  164.      MoveTo(PaintHdc,R.Left+2,R.Top+15);
  165.      LineTo(PaintHdc,R.Right-3,R.Top+15);
  166.      LineTo(PaintHdc,R.Right-3,R.Top+2);
  167.  
  168.      DeleteObject(SelectObject(PaintHdc,OldPen));
  169.      Pen:=CreatePen(ps_Solid,1,GetSysColor(color_btnShadow));
  170.      OldPen:=SelectObject(PaintHDC,Pen);
  171.      MoveTo(PaintHdc,R.Left+2,R.Top+2);
  172.      LineTo(PaintHdc,R.Right-3,R.Top+2);
  173.      MoveTo(PaintHdc,R.Right-1,R.Top);
  174.      LineTo(PaintHdc,R.Right-1,R.Bottom);
  175.      MoveTo(PaintHdc,R.Left+2,R.Top+2);
  176.      LineTo(PaintHdc,R.Left+2,R.Top+15);
  177.  
  178.      DeleteObject(SelectObject(PaintHDC,OldPen));     
  179. END;
  180.  
  181. (*************************** TStatusLine Methods *************************)
  182.  
  183. { TStatusLine is an object descendant of TWindow. TStatusLine has a field
  184.   called Partitions, which is a collection of TPartitions.
  185.  
  186.   The InsertItem method is the method responsible for inserting new
  187.   TPartitions in the Partition collection.
  188.  
  189.   The Paint method draws the statusline, and iterates through the Partition
  190.   collection call each ones Paint method. This results in the entire
  191.   statusline being redrawn. }
  192.  
  193.  
  194. CONSTRUCTOR TStatusLine.Init(AParent : PWindowsObject; ATitle : PCHAR);
  195. BEGIN
  196.      TWindow.Init(AParent,ATitle);
  197.      WITH Attr DO BEGIN
  198.           Style := Style OR ws_Child OR ws_Border;
  199.      END;
  200.      Partitions:=New(PPartitionCollection,Init(1,1));
  201.      Setup;
  202. END;
  203.  
  204. PROCEDURE TStatusLine.InsertItem(StrLength : WORD; Proc : TPaintProc);
  205. BEGIN
  206.      IF Partitions^.Count=0 THEN BEGIN
  207.         Partitions^.Insert(New(PPartition,Init(@Self,Nil,0,StrLength,
  208.         Proc)));
  209.      END
  210.      ELSE BEGIN
  211.        Partitions^.Insert(New(PPartition,Init(@Self,NIL,PPartition(
  212.           Partitions^.At(Partitions^.Count-1))^.RightPosition,PPartition(
  213.           Partitions^.At(Partitions^.Count-1))^.RightPosition+StrLength,
  214.           Proc)));
  215.      END;
  216. END;
  217.  
  218. FUNCTION TStatusLine.GetPartition(Index : BYTE):PPartition;
  219. BEGIN
  220.      GetPartition:=NIL;
  221.      IF Partitions^.Count<>0 THEN BEGIN
  222.         GetPartition:=Partitions^.At(Index);
  223.      END;
  224. END;
  225.  
  226. PROCEDURE TStatusLine.Setup;
  227. BEGIN
  228. END;
  229.  
  230. PROCEDURE TStatusLine.Paint(PaintHDC : HDC; VAR PaintInfo : TPaintStruct);
  231. VAR
  232.    R         : TRect;
  233.    TheBrush  : HBrush;
  234.    Pen,
  235.    OldPen    : HPen;
  236.  
  237.    PROCEDURE CallPaint(P : PPartition);FAR;
  238.    BEGIN
  239.         P^.Paint(PaintHDC,PaintInfo);        
  240.    END;
  241.  
  242. BEGIN
  243.      GetClientRect(Parent^.HWindow,R);
  244.      MoveWindow(HWindow,0,R.Bottom-18,R.Right-R.Left,R.Bottom,TRUE);
  245.  
  246.      GetClientRect(HWindow,R);
  247.      IF Partitions^.Count<>0 THEN BEGIN
  248.         R.Left:=PPartition(
  249.               Partitions^.At(Partitions^.Count-1))^.RightPosition;
  250.      END;
  251.      TheBrush:=CreateSolidBrush(GetSysColor(color_BtnFace));
  252.      FillRect(PaintHdc,R,TheBrush);
  253.      DeleteObject(TheBrush);
  254.  
  255.      Pen:=CreatePen(ps_Solid,1,RGB(255,255,255));
  256.      OldPen:=SelectObject(PaintHDC,Pen);
  257.      MoveTo(PaintHDC,R.Left,R.Top);
  258.      LineTo(PaintHDC,R.Right,R.Top);
  259.      MoveTo(PaintHdc,R.Left,R.Top);
  260.      LineTo(PaintHdc,R.Left,R.Bottom);
  261.      MoveTo(PaintHdc,R.Left+2,R.Top+15);
  262.      LineTo(PaintHdc,R.Right-3,R.Top+15);
  263.      LineTo(PaintHdc,R.Right-3,R.Top+2);
  264.  
  265.      DeleteObject(SelectObject(PaintHdc,OldPen));
  266.      Pen:=CreatePen(ps_Solid,1,GetSysColor(color_btnShadow));
  267.      OldPen:=SelectObject(PaintHDC,Pen);
  268.      MoveTo(PaintHdc,R.Left+2,R.Top+2);
  269.      LineTo(PaintHdc,R.Right-3,R.Top+2);
  270.      MoveTo(PaintHdc,R.Right-1,R.Top);
  271.      LineTo(PaintHdc,R.Right-1,R.Bottom);
  272.      MoveTo(PaintHdc,R.Left+2,R.Top+2);
  273.      LineTo(PaintHdc,R.Left+2,R.Top+15);
  274.  
  275.      DeleteObject(SelectObject(PaintHdc,OldPen));
  276.  
  277.      Partitions^.ForEach(@CallPaint);
  278. END;
  279.  
  280.  
  281. DESTRUCTOR TStatusLine.Done;
  282. BEGIN
  283.      Dispose(Partitions,Done);
  284.      TWindow.Done;
  285. END;
  286.  
  287. END.
  288.  
  289. {------------------------   DEMO -------------------------}
  290.  
  291.  (*************************************************************************
  292.  *                                                                        *
  293.  * STATUSEX.PAS - example program using the STATUS unit.                  *
  294.  *                By Thomas S. Carlisle                                   *
  295.  *                                                                        *
  296.  *                                                                        *
  297.  * This program sets up an example application demonstrating the use of   *
  298.  * the STATUS unit. A main window is created that has a statusline with   *
  299.  * a single partition that will display the current time.                 *
  300.  *                                                                        *
  301.  * I picked a clock example because it demonstrates how the main window   *
  302.  * can communicate with the statusline to tell it a certain partition     *
  303.  * needs to be redrawn.                                                   *
  304.  *                                                                        *
  305.  *************************************************************************)
  306.  
  307. PROGRAM StatusEx;
  308. USES
  309.     WObjects,WinTypes,WinProcs,Status,WinDOS,Strings;
  310.  
  311. CONST
  312.      wm_UpdateTime   = $0400;  { User defined message }
  313.       
  314. TYPE
  315.     TimeRec = RECORD           
  316.             Hour,
  317.             Min     : WORD;
  318.     END;
  319.  
  320.     PMyStatusLine = ^TMyStatusLine;
  321.  
  322.     TMyStatusLine = OBJECT(TStatusLine)    
  323.         PROCEDURE Setup;VIRTUAL;
  324.         PROCEDURE UpdateTime(VAR Msg : TMessage);
  325.              VIRTUAL wm_First + wm_UpdateTime;
  326.     END;
  327.  
  328.     PMyWindow = ^TMyWindow;
  329.  
  330.     TMyWindow = OBJECT(TWindow)
  331.          StatusLine    : PMyStatusLine;
  332.          CONSTRUCTOR Init(AParent : PWindowsObject; ATitle : PCHAR);
  333.          PROCEDURE SetupWindow;VIRTUAL;
  334.          DESTRUCTOR Done;VIRTUAL;
  335.          PROCEDURE Timer(VAR Msg : TMessage);VIRTUAL wm_Timer;
  336.     END;
  337.  
  338.     TMyApp = OBJECT(TApplication)
  339.            PROCEDURE InitMainWindow;VIRTUAL;
  340.     END;
  341.  
  342.  
  343. (********************************* Globals **************************)
  344.  
  345. VAR
  346.    OldTime      : TimeRec;    { OldTime will be used to keep track of
  347.                                 whether or not the time has changed and
  348.                                 needs to be redrawn                       }
  349.  
  350. PROCEDURE Clock(PaintHdc : HDC; VAR PaintInfo : TPaintStruct);FAR;
  351.  
  352. { This procedure MUST be declared as FAR because it is passed as a
  353.   parameter to the statusline, so the statusline will know what procedure
  354.   to call when the statusline needs to be drawn. The statusline draws the
  355.   actual box, but this procedure must fill in the text.
  356.  
  357.   Note the parameter list. It is mandatory, but also convenient. You will
  358.   need to use the PaintHDC as the device context for your text output. The
  359.   PaintInfo is there just in case you need it. All procedures designed to be
  360.   passed to the statusline to be used to fill in the statusline partitions
  361.   MUST have these two parameters!
  362.  
  363.   This procedure simply fills the box with the current time.              }
  364.  
  365. VAR
  366.    TimeStr      : ARRAY[0..5] OF CHAR;
  367.    Hour,
  368.    Minute,
  369.    Sec,
  370.    HSec         : WORD;
  371.    TempStr,
  372.    Temp1        : ARRAY[0..2] OF CHAR;
  373. BEGIN
  374.      StrCopy(TimeStr,' ');
  375.      GetTime(Hour,Minute,Sec,HSec);
  376.      OldTime.Hour:=Hour;          { Fill in OldTime record for future use }
  377.      OldTime.Min:=Minute;
  378.      Str(Hour,TempStr);           { Build the string that holds the time }
  379.      StrCat(TimeStr,TempStr);
  380.      StrCopy(TempStr,':');
  381.      StrCat(TimeStr,TempStr);
  382.      Str(Minute,TempStr);
  383.      IF StrLen(TempStr)=1 THEN BEGIN
  384.          StrCopy(Temp1,'0');
  385.          StrCat(Temp1,TempStr);
  386.          StrCopy(TempStr,Temp1);
  387.      END; 
  388.      StrCat(TimeStr,TempStr);
  389.      TextOut(PaintHdc,3,1,TimeStr,StrLen(TimeStr));   { Output the time }
  390. END;
  391.  
  392. (************************ TMyStatusLine Methods ************************)
  393.  
  394. PROCEDURE TMyStatusLine.UpdateTime(VAR Msg : TMessage);
  395.  
  396. { This procedure is a response method for TMyStatusLine. It responds to
  397.   the wm_UpdateTime user defined message. The procedure first checks
  398.   the current time against the time in OldTime. If they are different,
  399.   then the clock status window is invalidated, to force it to be redrawn
  400.   with the new time.
  401.  
  402.   The reason this program is setup to keep track of the OldTime, and have
  403.   this procedure check it, is to avoid flicker that occurs if the time
  404.   is updated when it isn't necessary.                                    }
  405.  
  406. VAR
  407.    Hour,Min,Sec,HSec : WORD;
  408. BEGIN
  409.      GetTime(Hour,Min,Sec,HSec);
  410.      IF (OldTime.Hour<>Hour) OR (OldTime.Min<>Min) THEN
  411.           InvalidateRect(GetPartition(0)^.HWindow,NIL,TRUE);
  412. END;
  413.  
  414. PROCEDURE TMyStatusLine.Setup;
  415.  
  416. { Overrides the inherited Setup method. This setup method inserts one
  417.   statusline partition in the status line. }
  418.  
  419. BEGIN
  420.      InsertItem(75,Clock);  { This inserts a new item in the statsuline.
  421.                               The first parameter is the length (in pixels)
  422.                               of the desired statusline partition. The
  423.                               second parameter is the procedure this new
  424.                               partition will call whenever it needs to be
  425.                               redrawn. As stated earlier, the statusline
  426.                               takes care of drawing the statusline and it's
  427.                               partitions, but the procedure passed here is
  428.                               responsible for filling the partition with
  429.                               text }
  430.  
  431.                             { If you need more than one partition,
  432.                               simply add more InsertItem statements. Each
  433.                               one can be passed a length and procedure
  434.                               parameter. Very powerful.                  }
  435.  
  436. END;
  437.  
  438. (************************* TMyWindow Methods ***************************)
  439.  
  440. CONSTRUCTOR TMyWindow.Init(AParent : PWindowsObject; ATitle : PCHAR);
  441.  
  442. { TMyWindow is a descendant of TWindow. The only difference is it has a
  443.   StatusLine.                                                              }
  444.  
  445. BEGIN
  446.      TWindow.Init(AParent,ATitle);
  447.      Statusline:=New(PMyStatusLine,Init(@Self,Nil));
  448. END;
  449.  
  450. PROCEDURE TMyWindow.SetupWindow;
  451.  
  452. { SetupWindow is needed in this application to start the timer that will
  453.   be used to spark messages every second to make sure the statusline clock
  454.   is kept up to date.                                                      }
  455.  
  456. BEGIN
  457.      TWindow.SetupWindow;
  458.      IF SetTimer(HWindow,1,1000,NIL) = 0 THEN
  459.         MessageBox(HWindow,'ERROR','Timer not available',mb_OK);
  460. END;
  461.  
  462. PROCEDURE TMyWindow.Timer(VAR Msg : TMessage);
  463.  
  464. { Responds to wm_Timer messages. First checks to make sure the incomming
  465.   message is ours (ID=1). If it is, it sends a wm_UpdateTime message
  466.   to the statusline. That is the message the statusline responds to by
  467.   updating the time, if it has changed.                                   }
  468.    
  469. BEGIN
  470.      IF Msg.wParam=1 THEN BEGIN
  471.         SendMessage(StatusLine^.HWindow,wm_UpdateTime,0,0);     
  472.      END;     
  473. END;
  474.  
  475. DESTRUCTOR TMyWindow.Done;
  476. { Cleans up by killing the timer we started, and disposing the statusline }
  477. BEGIN
  478.      KillTimer(HWindow,1);
  479.      Dispose(StatusLine,Done);
  480.      TWindow.Done;
  481. END;
  482.  
  483. (****************************** TMyApp Methods ************************)
  484.  
  485. PROCEDURE TMyApp.InitMainWindow;
  486. { Gets our main window (TMyWindow) in action }
  487. BEGIN
  488.      MainWindow:=New(PMyWindow,Init(NIL,'Test'));
  489. END;
  490.  
  491. VAR
  492.    MyApp   : TMyApp;
  493. BEGIN
  494.      MyApp.Init('Test');
  495.      MyApp.Run;
  496.      MyApp.Done;
  497. END.